package pages;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;

import database.DBException;
import database.DBUtils;

import templates.Template;

public class XSLT {

	private static final String xslsTableName = "XSLs";

	/**
	 * Applies XSL on XML
	 * 
	 * @param xml
	 * @param xslName
	 * @param xslType
	 * @return string with the result
	 */
	public static String applyXSL(String xml, String xslName, XSLType xslType) {
		ByteArrayInputStream xmlStream = null;
		ByteArrayInputStream xslStream = null;
		try {
			// creating xml inputstream
			byte currentXMLBytes[] = xml.getBytes();
			xmlStream = new ByteArrayInputStream(currentXMLBytes);

			// creating xsl inputstream
			byte currentXSLBytes[] = null;
			try {
				currentXSLBytes = getXSL(xslName, xslType).getBytes();
			} catch (DBException e) {
				currentXSLBytes = getDefaultXSL(xslType).getBytes();
			}

			xslStream = new ByteArrayInputStream(currentXSLBytes);

			// creating outputstream
			ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

			TransformerFactory tFactory = TransformerFactory.newInstance();

			Transformer transformer = tFactory
					.newTransformer(new javax.xml.transform.stream.StreamSource(
							xslStream));

			transformer.transform(new javax.xml.transform.stream.StreamSource(
					xmlStream), new javax.xml.transform.stream.StreamResult(
					byteArrayOutputStream));
			return byteArrayOutputStream.toString().substring(38);
		} catch (Exception e) {
			return null;
		} finally {
			if (xmlStream != null) {
				try {
					xmlStream.close();
				} catch (IOException e) {
				}
			}
			if (xslStream != null) {
				try {
					xslStream.close();
				} catch (IOException e) {
				}
			}
		}
	}

	/**
	 * Reads XSL text from DB
	 * 
	 * @param name
	 * @param type
	 * @return String with XSL
	 * @throws DBException
	 */
	private static String getXSL(String name, XSLType type) throws DBException {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			String query = "SELECT `content` FROM `" + xslsTableName
					+ "` WHERE `name` = ? AND `xmlType` = ? LIMIT 1";
			conn = DBUtils.getConnection();
			stmt = conn.prepareStatement(query);
			stmt.setString(1, name);
			stmt.setString(2, type.toString());
			rs = stmt.executeQuery();
			if (!rs.next()) {
				throw new DBException("XSL not found");
			}
			return rs.getString("content");
		} catch (SQLException e) {
			throw new DBException("Can't load Instruments List: "
					+ e.getMessage(), e);
		} finally {
			DBUtils.close(rs);
			DBUtils.close(stmt);
			DBUtils.close(conn);
		}
	}

	/**
	 * Chooses any appropriate XSL from DB
	 * 
	 * @param type
	 * @return XSL string
	 * @throws DBException
	 */
	private static String getDefaultXSL(XSLType type) throws DBException {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			String query = "SELECT `content` FROM `" + xslsTableName
					+ "` WHERE `xmlType` = ? LIMIT 1";
			conn = DBUtils.getConnection();
			stmt = conn.prepareStatement(query);
			stmt.setString(1, type.toString());
			rs = stmt.executeQuery();
			if (!rs.next()) {
				throw new DBException("XSL not found");
			}
			return rs.getString("content");
		} catch (SQLException e) {
			throw new DBException("Can't load Instruments List: "
					+ e.getMessage(), e);
		} finally {
			DBUtils.close(rs);
			DBUtils.close(stmt);
			DBUtils.close(conn);
		}
	}

	private static final String templateName = "xsl_name_select";
	private static final String rowTemplateName = "xsl_name_option";

	/**
	 * Generates combo-box with all available XSLs of specified type
	 * 
	 * @param type
	 * @param selectedName
	 * @return
	 * @throws InternalErrorException
	 * @throws DBException
	 */
	public static Template getXSLs(XSLType type, String selectedName)
			throws InternalErrorException, DBException {
		Template template = new Template(templateName);
		Template rowTemplate = new Template(rowTemplateName);
		String rowsText = "";
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			String query = "SELECT `name` FROM `" + xslsTableName
					+ "` WHERE `xmlType` = ?;";
			conn = DBUtils.getConnection();
			stmt = conn.prepareStatement(query);
			stmt.setString(1, type.toString());
			rs = stmt.executeQuery();
			while (rs.next()) {
				String name = rs.getString("name");
				rowTemplate.addChange("name", name);
				rowTemplate.addChange("value", name);
				rowTemplate.addChange("selected",
						name.equals(selectedName) ? "selected=\"selected\""
								: "");
				rowsText += rowTemplate.applyChanges();
			}

			template.addChange("xml_name_options", rowsText);
			return template;
		} catch (SQLException e) {
			throw new DBException("Can't load Instruments List: "
					+ e.getMessage(), e);
		} finally {
			DBUtils.close(rs);
			DBUtils.close(stmt);
			DBUtils.close(conn);
		}
	}

}
